package DateTime::Cursor::TestScaffolding::Iterators;

use warnings;
use strict;
use Carp;

use version; our $VERSION = qv('0.0.1');
use base qw( Exporter );
our @EXPORT = qw( calculate_number_of_iterator_tests run_iterator_tests );

use Test::More;

#use Test::More qw(no_plan);
use Data::Dumper;

use DateTime::Format::Mail;
use DateTime::TimeZone;

use DateTime::Cursor::TestScaffolding::Utilities
  qw (nop_tests pretty_print cmp_cursors str_cmp_dt_to_cursor num_cmp_dt_to_cursor );

use DateTime::Cursor;

# my @test_offsets = ('default', 0, -1, 1, 24, 60, 52, 365); 
my $_base_number_of_iterator_tests = 22; # * (scalar @test_offsets);

sub calculate_number_of_iterator_tests {
	my $rh_args         = $_[0];
	my $number_of_tests = $_base_number_of_iterator_tests;
	foreach my $key ( keys %{$rh_args} ) {
		my $num_factors = scalar @{ $rh_args->{$key} };
		$number_of_tests *= $num_factors;
	}
	return $number_of_tests;
}

sub run_iterator_tests {
	my $rh_args = $_[0];
	confess "undefined args" unless defined $rh_args;

	my $seed_dt = DateTime->now( time_zone => 'UTC' );
	foreach my $interval ( @{ $rh_args->{'intervals'} } ) {
		foreach my $tz ( @{ $rh_args->{'timezones'} } ) {
			foreach my $formatter ( @{ $rh_args->{'formatters'} } ) {
		                foreach my $offset (@{$rh_args->{'offsets'} } ) {	
             				_iterator_test_case( $seed_dt, $interval, $tz, $formatter, $offset );
				}
			}	
		}
	}
}

sub _iterator_test_case {
	my ( $seed_dt, $interval, $tz, $formatter, $offset ) = @_;

	#
	# set baseline
	#
	my $cursor_control = DateTime::Cursor->new(
		{ pivot => $seed_dt->clone(), interval => $interval } );
	my $cursor_test = DateTime::Cursor->new(
		{
			pivot     => $seed_dt->clone(),
			formatter => $formatter,
			timezone  => $tz,
			interval  => $interval
		}
	);
	my $dt_control = $seed_dt->clone();
	$dt_control->set_time_zone($tz);

	cmp_cursors( $cursor_control, $cursor_test, 0,
		"compare control cursor with umodified test cursor" );
	my $msg = "compare control datetime with unmodified test cursor";
	str_cmp_dt_to_cursor( $dt_control, $cursor_test, 0, $formatter, $msg );
	num_cmp_dt_to_cursor( $dt_control, $cursor_test, 0, $msg );

        my ($cmp1, $cmp2, $cmp3) = (-1, 0, 1);
        if ( ('default' ne $offset) and ($offset == 0) ) {
        	($cmp1, $cmp2, $cmp3) = (0, 0, 0); 
        }               
	
	#
	# bump forward
	#
	if ('default' eq $offset) { 
		$cursor_test->scroll_forward();
	} else {  
		$cursor_test->scroll_forward($offset);
	}
	cmp_cursors( $cursor_control, $cursor_test, $cmp1,
"compare control cursor with test cursor after calling scroll_forward($offset) on test cursor"
	);

	#
	# bump backward
	#
	if ('default' eq $offset) { 
		$cursor_test->scroll_backward();
	} else { 
		$cursor_test->scroll_backward($offset);
	}
	cmp_cursors( $cursor_control, $cursor_test, $cmp2,
"compare control cursor with test cursor after calling scroll_forward($offset) then scroll_backward($offset) on test cursor"
	);

	#
	# bump backward again
	#
	if ('default' eq $offset) {
		$cursor_test->scroll_backward();
	} else {
		$cursor_test->scroll_backward($offset);
	}
	cmp_cursors( $cursor_control, $cursor_test, $cmp3,
"compare control cursor with test cursor after calling scroll_forward($offset) then scroll_backward($offset) twice on test cursor"
	);
	return;
}

1;
